﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.HomeServer.SDK.Interop.v1;
using System.IO;
using System.Runtime.InteropServices;

namespace RouterControl.Whs
{
	public sealed class ApplicationFolders
	{
		public static readonly string HomeServerDir = (Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + "\\Windows Home Server");
        public static readonly string WindowsSystem32 = Environment.GetFolderPath(Environment.SpecialFolder.System);

		// keep in sync with:
		// log4net.config: file value
		// RouterControl.WixSetup/Product.wxs RouterControlAppFolderNonDup and RouterControlAppFolderDup properties
		// RouterControl.Diag/RouterControl.Diag.exe.log4net: file value
		public static readonly Guid NonDuplicatedId = new Guid("3EB3E1B1-5A8B-45E3-9F9A-573D1088B3B5" /*msi product id*/);
		public static readonly Guid DuplicatedId = new Guid("3EB3E1B1-5A8B-45E3-9F9A-573D1088B3B6" /*msi product id+1*/);

		private static object _instanceCreateLock = new object();
		private static volatile ApplicationFolders _instance = null;

		private readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(ApplicationFolders));
		private WHSInfoClass _whs;
		private object _nonDuplicatedCreateLock = new object();
		private object _duplicatedCreateLock = new object();

		public static ApplicationFolders Instance
		{
			get
			{
				if (_instance == null)
				{
					lock (_instanceCreateLock)
					{
						if (_instance == null)
						{
							_instance = new ApplicationFolders();
						}
					}
				}

				return _instance;
			}
		}

		public IApplicationFolder NonDuplicated
		{
			get
			{
				try
				{
					var f = GetApplicationFolderSafe(NonDuplicatedId);
	
					if (f == null)
					{
						lock (_nonDuplicatedCreateLock)
						{
							_log.InfoFormat(
								"Creating application folder: {1} ({0})",
								NonDuplicatedId,
								Properties.Constants.ApplicationFolderNonDuplicated
								);

							f = GetApplicationFolderSafe(NonDuplicatedId);
	
							if (f == null)
							{
								f = _whs.CreateApplicationFolder(NonDuplicatedId, Properties.Constants.ApplicationFolderNonDuplicated);
	
								f.IsDuplicated = 0;
							}
						}
					}
	
					return f;
				}
				catch (Exception e)
				{
					_log.Fatal("Failed to get non-duplicated application folder: " + NonDuplicatedId.ToString(), e);

					throw;
				}
			}
		}

		public DirectoryInfo NonDuplicatedDir
		{
			get { return new DirectoryInfo(this.NonDuplicated.Path); }
		}

		public IApplicationFolder Duplicated
		{
			get
			{
				try
				{
					var f = GetApplicationFolderSafe(DuplicatedId);
	
					if (f == null)
					{
						lock (_duplicatedCreateLock)
						{
							_log.InfoFormat(
								"Creating application folder: {1} ({0})",
								DuplicatedId,
								Properties.Constants.ApplicationFolderDuplicated
								);

							f = GetApplicationFolderSafe(DuplicatedId);
	
							if (f == null)
							{
								f = _whs.CreateApplicationFolder(DuplicatedId, Properties.Constants.ApplicationFolderDuplicated);
	
								// TODO: wait for MS to implement duplication on app folders
								try
								{
									f.IsDuplicated = 1;
								}
								catch (NotImplementedException e)
								{
									_log.Warn("Folder duplication still unsupported for application folders: " + DuplicatedId.ToString(), e);
								}
							}
						}
					}
	
					return f;
				}
				catch (Exception e)
				{
					_log.Fatal("Failed to get duplicated application folder: " + DuplicatedId.ToString(), e);

					throw;
				}
			}
		}

		public DirectoryInfo DuplicatedDir
		{
			get { return new DirectoryInfo(this.Duplicated.Path); }
		}

		private IApplicationFolder GetApplicationFolderSafe(Guid id)
		{
			try
			{
				return _whs.GetApplicationFolder(id);
			}
			catch (COMException e)
			{
				if ((uint)e.ErrorCode == 0x80070490 /*not found*/)
					return null;

				throw;
			}
		}

		private ApplicationFolders()
		{
			if (_log.IsDebugEnabled)
				_log.Debug("Creating singleton");

			try
			{
				_whs = new WHSInfoClass();
	
				_whs.Init(Properties.Constants.ApplicationName);
			}
			catch (Exception e)
			{
				_log.Fatal("Failed to create singleton", e);

				throw;
			}
		}


	}
}
